/*	This File is a simple example to show how to retrieve 
	some inforamtions from the symboltable of a project
	Commandline:
	test <project_file_with_full_path [optional_server_host]
*/

#if __GNUG__ >= 2
#  pragma implementation
#endif

#include "c_symTab_API.h"			/* The interface header to the library	*/
#include <stdio.h>					/* need it for fprintf					*/

/* 							
	*		Declarations for test-functions							
*/
void	PrintCol		( si_Collection* ); 
void	PrintFiles		( si_Collection* );
void	DumpFileVersion ( si_Collection* );
void	PrintMethodPair	( si_Collection *col );
void	PrintClassRelations(  si_Collection *col );
void	FlatPrintCol	( si_Collection *col );
void 	ParseArgs		( int argc, char** argv, char**, char**, char** );
si_Item*MakeVersionItem	( si_Item*, char* , si_Type );
/*							
	*		Macro for easier structure access						
*/
#define	TAKE(i)	i->take._incl->

/*							
	*		The main function										
*/
int main ( int argc, char *argv[] )		
{
	SNiFFACCESS slot;					/* the access slot for further calls */
	si_Collection	*full  	= NULL;
	si_Collection	*other	= NULL;
	int				dbg;
	char			*host   = NULL;		// host where sniff runs if needed
	char			*proj	= NULL;		// project to open
	char			*session= NULL;		// SNiFF+ session to use
	ParseArgs( argc, argv, &host, &proj, &session );
	
	__si__module__init( ); 		/* initialize Symtab Interface */
/*
	*		Connect to a Server. If more than 1 argument then use the server option 
*/
	slot = si_open( session, host );	
	if( !slot )
		fprintf( stderr, "ERROR, can't connect to SNiFF+\n" );
		
	if( slot && si_open_project( slot, proj ) )
	{
/*
	*		Ask SNiFF+ for the Full hierarchy including all subitems
*/
		full = si_Query(eQImplFiles,eSGlobal,0);

//		PrintCol	( full );
		
		DumpFileVersion( full );

		dbg  = si_close_project( slot, proj );
		dbg  = si_open_project ( slot, proj )	;
		other= si_Query(eQOOFullHierarchy,eSHierarchy,0);
		
		PrintCol	( other );
		if( other->first && TAKE(other->first)subClass )
		{
			PrintFiles	( TAKE(other->first)subClass );
		}
		if( other->first && TAKE(other->first)subItems )
		{
			PrintMethodPair( TAKE(other->first)subItems );
		} 
		if( other->first && TAKE(other->first)subClass );
		{
			PrintClassRelations( TAKE(other->first)subClass );
			PrintClassRelations( other );
		}
		si_close_project( slot, proj );
	}
	si_exit(slot);

return 0;
}

#ifdef __cplusplus
extern "C" {
#endif

void ParseArgs( int argc, char**argv, char** host, char** proj, char** session )
{
	char* 	p   = 0;
	int		arg = 0;
	
	while( ++arg < argc )
	{
		p = argv[arg];
		if( *p++ == '-' )
			switch( *p++ )
			{
				case 's':
				case 'S':
					*session = p;
					break;
				case 'p':
				case 'P':
					*proj = p;
					break;
				case 'h':
				case 'H':
					*host = p;
					break;
				default:
					fprintf( stderr,"Error with unknown argument %d : %s.\n", arg, argv[arg] );
			}
	}
}

/* debug functions*/
extern char* debugTokenStr[];
extern char* debugScopeStr[];


void ptk( si_Item* itm )
{
	fprintf(stderr,"hash?: %s hval: %d isInd: %s ",(itm->take._hash)?"TRUE":"FALSE",itm->_hash,(itm->take._incl)?"TRUE":"FALSE");
}

void pit( si_Item* itm )
{
	char*	typeStr = debugTokenStr[(itm&&itm->type<eTLAST)?itm->type:eTLAST ];
	char*	scopeStr= NULL;
	fprintf(stderr,"\nName %s, Type %s",((itm)?(char*)itm->name:"NULL_PTR"), typeStr );
	if( itm && itm->take._incl)
	{
		scopeStr 	= debugScopeStr[(TAKE(itm)scope >=0 && TAKE(itm)scope < eSLAST )?TAKE(itm)scope :eSLAST ];
		fprintf(stderr,"\nSubI :%s\t SubC: %s",(TAKE(itm)subItems)?"TRUE":"FALSE",(TAKE(itm)subClass)?"TRUE":"FALSE");
		fprintf(stderr,"\nSuper:%s\t From: %s",(TAKE(itm)superClass)?"TRUE":"FALSE",(TAKE(itm)from)?"TRUE":"FALSE");
		fprintf(stderr,"\nScope:%s\t X:    %d Y:%d",scopeStr,TAKE(itm)sPos,TAKE(itm)ePos);
		if( TAKE(itm)typeStr && TAKE(itm)declStr )
		{
			fprintf(stderr,"\nType %s, Decl %s ",TAKE(itm)typeStr,TAKE(itm)declStr);
		}
		fprintf(stderr,"\nMagic %08d\n",TAKE(itm)__magic__cooky__ );
	}
}
/*debug functions end*/
#ifdef __cplusplus
}
#endif


void PrintFiles ( si_Collection *col )
{
	si_Item 		*itm = col->first;
	si_Item			*file= NULL;
	si_Collection	*res = NULL;
	if( itm )
	{
		do
		{
			if( itm->type == eTScope )
			{
/* 
	print item that shows visibility and scope and template args of superclass
*/
				fprintf( stderr,"\n VISIBILITY / SCOPE / TEMPLATE ARGS");
				pit( itm );				
/*
	Get the superclass item that follows
*/									
				itm = itm->next;
				if( !itm )
					break;				/* get out if item is NULL: ERROR ! */
			}
			pit( itm );
			res = si_Query(eQFindSym,(si_Scope)eTFile,itm);
			if( res && res->first )
			{
				pit( res->first );
				if( res->first->type == eTFile )
				{
					file = (res->first->take._hash)?getHashed(res->first):res->first;
					if( file && TAKE(file)subItems )
						PrintCol(TAKE(file)subItems);
				}
			}
		}while( (itm = itm->next) );
	}
}
void PrintMethodPair( si_Collection *col )
{
	si_Item 		*itm = col->first;
	si_Collection	*res = NULL;
	if( itm )
	{
		do
		{
			if( itm->type == eTMethodI || itm->type == eTMethodD )
			{
				pit( itm );
				res = si_Query( eQFindSym,(si_Scope)((itm->type==eTMethodI)?eTMethodD:eTMethodI), itm );
				if( res && res->first )
				{
					pit( (res->first->take._hash)?getHashed(res->first):res->first );
					res = si_Query( eQFindSym, (si_Scope)eTFile, res->first );
					if( res && res->first )
					{
						pit( (res->first->take._hash)?getHashed(res->first):res->first );
					}
				}
			}
		}while( (itm = itm->next) );
	}
}

si_Item	* MakeVersionItem	( si_Item* fileItem, char* version, si_Type type )
{
	si_Item * itm = si_cloneItem( fileItem );
	
	itm->name = version;
	itm->type = type;
return itm;
}

void DumpFileVersion ( si_Collection* col )
{
	si_Item 		*itm = col->first;
	si_Collection	*res = NULL;

	if( itm )
	{
		do
		{
			if( itm->type == eTFile )
			{
				si_Item* req = MakeVersionItem( itm, "HEAD", eTHead ); 
				res = si_Query( eQFileVersionConfig, 0 , req );
				if( res && res->first )
					pit( res->first );
			}
		} while( itm = itm->next );
//		eQFileVersionConfig
	}
}

void PrintClassRelations(  si_Collection *col )
{
	if( col )
	{
		si_Item 		*itm = col->first;
		si_Collection	*res = NULL;
		if( itm )
		{
			do
			{
				if( itm->type == eTClass  || itm->type == eTScope )
				{
					if( itm->type == eTScope )
					{
/* 
	print item that shows visibility and scope and template args of superclass
*/
						fprintf( stderr,"\n VISIBILITY / SCOPE / TEMPLATE ARGS");
						pit( itm );				
/*
	Get the superclass item that follows
*/									
						itm = itm->next;
						if( !itm )
							break;				/* get out if item is NULL: ERROR ! */
					}
					fprintf( stderr,"\n Crossreferences of class! ");
					pit( itm );
					res = si_Query(eQReferredBy,eSGlobal,itm);
					if( res && res->first )
					{
						fprintf( stderr,"\n\t Refered by:");
						FlatPrintCol( res );
					}
					res = si_Query(eQReferresTo,eSGlobal,itm);
					if( res && res->first )
					{
						fprintf( stderr,"\n\t Referes to:");
						FlatPrintCol( res );
					}
				}
			}while( (itm = itm->next) );
		}
	}
}
void FlatPrintCol( si_Collection *col )
{
	if( col )
	{
		si_Item		*itm = col->first;
		if( itm )
		{
			do
			{
				pit( (itm->take._hash)?getHashed(itm):itm );
			}while( itm = itm->next );
		}
	}
}
void PrintCol( si_Collection *col )
{
	si_Item *itm = (col && col->first)?col->first:NULL;
	si_Item *tmp = NULL;
	if( itm )
	{
		do
		{
			if( itm->type == eTScope )
				fprintf( stderr,"\n VISIBILITY / SCOPE / TEMPLATE ARGS");
			fprintf( stderr,"\n*******\t%s\t*******\n",itm->name);
			pit( itm );
			tmp = itm;
			if( itm->take._hash )
			{ 
			/*	fprintf( stderr, "\n>\t H A S H E D  I T E M ! \n");*/
				if( itm->type != eTScope )
					tmp = getHashed(itm);
			}
			if( tmp && TAKE(tmp)subItems )
			{
				fprintf( stderr,"\n>\tSUBITEMS ");
				PrintCol( TAKE(tmp)subItems );
			}
			if( tmp && TAKE(tmp)subClass )
			{
				fprintf( stderr,"\n>\tSUBCLASSES ");
				if( !itm->take._hash )
					PrintCol( TAKE(tmp)subClass );
			}
			if( tmp && TAKE(tmp)superClass )
			{
				fprintf( stderr,"\n>\tSUPERCLASSES ");
				if( !itm->take._hash )
				pit( TAKE(tmp)from );
			}
		}while( (itm = itm->next) );
	}
}
